home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 49 / Amiga Format CD49 (2000-01-17)(Future Publishing)(GB)(Track 1 of 3)[!][issue 2000-02].iso / -in_the_mag- / news / csppc233fix / csppc233fix_ppc.c < prev    next >
C/C++ Source or Header  |  1999-12-14  |  9KB  |  285 lines

  1. /*
  2.  *  LRBug.c
  3.  *
  4.  *  Try to work around what seems to be a hardware bug of CyberstormPPC
  5.  *  604e/233 cards.
  6.  *
  7.  *  Written by Emmanuel Lesueur lesueur@club-internet.fr
  8.  *
  9.  *  This code is in the public domain. You can do whatever you want with it.
  10.  *
  11.  *
  12.  *  CLI Usage:
  13.  *      LRBug NOREQ/S,QUIET/S,NOWAIT/S
  14.  *
  15.  *  NOREQ: don't ask before attempting to restart a task.
  16.  *  QUIET: don't write messages with kprinf() when restarting a task.
  17.  *  NOWAIT: don't install a handler, just restart crashed tasks and quit.
  18.  *
  19.  *  WB Usage:
  20.  *      Tooltypes NOREQ, QUIET, and NOWAIT, with the same meaning.
  21.  *
  22.  *  To remove the handler, send a CTRL-C.
  23.  *
  24.  *
  25.  *  Object:
  26.  *      Install an exception handler to catch exceptions caused by a
  27.  *  corrupted LR (bit 0 or 2 incorrectly set). When one is caught,
  28.  *  clear the bad bit and restart the task.
  29.  *
  30.  *  Issue:
  31.  *      Unfortunately, I don't know of any way to fall back to the default
  32.  *  exception handler for exceptions that are not of the "bad LR" type. So
  33.  *  in that case, I just display a small message via kprintf() and let the
  34.  *  user run PPCShowTrap to get the full register/MMU/stack dump.
  35.  *
  36.  *
  37.  *  To compile with SAS/C 6.58:
  38.  *      sc resetopts cpu=68040 params=registers nostackcheck optimize
  39.  *         optimizesize link stripdebug nostartup lib lib:debug.lib LRBug.c
  40.  *
  41.  *  To compile with gcc:
  42.  *      gcc -o LRBug -O2 -m68040 -nostdlib LRBug.c -ldebug
  43.  *
  44.  *  To compile with vbcc:
  45.  *      vc -o LRBug -O2 -cpu=68040 -nostdlib LRBug.c -lamiga -lppc -ldebug
  46.  *
  47.  *  Others:
  48.  *      I don't know, but: SHOULD BE LINKED WITH NO STARTUP !
  49.  */
  50.  
  51. #include <stdio.h>
  52. #include <string.h>
  53. #include <exec/ports.h>
  54. #include <dos/dos.h>
  55. #include <intuition/intuition.h>
  56. #include <workbench/startup.h>
  57. #include <powerup/ppclib/ppc.h>
  58. #include <powerup/ppclib/tasks.h>
  59. #include <proto/exec.h>
  60. #include <proto/dos.h>
  61. #include <proto/intuition.h>
  62. #include <proto/icon.h>
  63. #include <powerup/proto/ppc.h>
  64.  
  65. #ifdef __SASC
  66. #   define SAVEDS       __saveds
  67. #   define ASM          __asm
  68. #   define REG(x,y)     register __##x y
  69. #elif defined(__GNUC__)
  70. #   define SAVEDS
  71. #   define ASM
  72. #   define REG(x,y)     y __asm__(#x)
  73. #elif defined(_DCC)
  74. #   define SAVEDS       __geta4
  75. #   define ASM
  76. #   define REG(x,y)     __##x y
  77. #elif defined(__STORM__)
  78. #   define SAVEDS       __saveds
  79. #   define ASM
  80. #   define REG(x,y)     register __##x y
  81. #elif defined(__VBCC__)
  82. #   define SAVEDS
  83. #   define ASM
  84. #   define REG(x,y)     __reg(#x) y
  85. #else
  86. #   error   add #defines for your compiler...
  87. #endif
  88.  
  89. typedef BOOL ASM hook_func(REG(a0,struct Hook* h),
  90.                            REG(a2,void* t),
  91.                            REG(a1,struct ExceptionMsg* em));
  92.  
  93. static void* maintask;
  94. static struct Hook* oldhook;
  95. static BOOL noreq,quiet;
  96.  
  97. struct Library* PPCLibBase;
  98. struct ExecBase *SysBase;
  99. struct IntuitionBase *IntuitionBase;
  100. struct DosLibrary *DOSBase;
  101. struct Library *IconBase;
  102.  
  103. void kprintf(const char*,...);
  104.  
  105. void install_handler(void);
  106. void scan_tasks_list(void);
  107.  
  108. /*
  109.  *  Program entry point. No startup code needed.
  110.  */
  111. int SAVEDS start(void) {
  112.     struct Process *proc;
  113.     struct WBStartup *wbmsg=NULL;
  114.     int ret=RETURN_FAIL;
  115.  
  116.     SysBase=*(struct ExecBase**)4;
  117.     proc=(struct Process*)FindTask(NULL);
  118.     if(!proc->pr_CLI) {
  119.         WaitPort(&proc->pr_MsgPort);
  120.         wbmsg=(struct WBStartup*)GetMsg(&proc->pr_MsgPort);
  121.     }
  122.  
  123.     if((DOSBase=(struct DosLibrary*)OpenLibrary("dos.library",36)) &&
  124.        (IntuitionBase=(struct IntuitionBase*)OpenLibrary("intuition.library",39))) {
  125.         if(PPCLibBase=OpenLibrary("ppc.library",46)) {
  126.             maintask=FindTask(NULL);
  127.  
  128.             if(proc->pr_CLI) {
  129.                 struct RDArgs *rda;
  130.                 LONG args[3]={0,0,0};
  131.  
  132.                 if(rda=ReadArgs("NOREQ/S,QUIET/S,NOWAIT/S",args,NULL)) {
  133.                     ret=RETURN_OK;
  134.                     noreq=args[0];
  135.                     quiet=args[1];
  136.                     if(args[2])
  137.                         scan_tasks_list();
  138.                     else
  139.                         install_handler();
  140.                     FreeArgs(rda);
  141.                 } else
  142.                     PrintFault(IoErr(),"Error: ");
  143.             } else {
  144.                 BPTR olddir=CurrentDir(wbmsg->sm_ArgList[0].wa_Lock);
  145.                 struct DiskObject *dob;
  146.                 if(IconBase=OpenLibrary("icon.library",36)) {
  147.                     if(dob=GetDiskObjectNew(wbmsg->sm_ArgList[0].wa_Name)) {
  148.                         ret=RETURN_OK;
  149.                         noreq=dob->do_ToolTypes &&
  150.                               FindToolType((UBYTE **)dob->do_ToolTypes,
  151.                                            (UBYTE *)"NOREQ");
  152.                         quiet=dob->do_ToolTypes &&
  153.                               FindToolType((UBYTE **)dob->do_ToolTypes,
  154.                                            (UBYTE *)"QUIET");
  155.                         if(dob->do_ToolTypes &&
  156.                            FindToolType((UBYTE **)dob->do_ToolTypes,
  157.                                         (UBYTE *)"NOWAIT"))
  158.                             scan_tasks_list();
  159.                         else
  160.                             install_handler();
  161.                         FreeDiskObject(dob);
  162.                     }
  163.                     CloseLibrary(IconBase);
  164.                 }
  165.                 CurrentDir(olddir);
  166.             }
  167.  
  168.             CloseLibrary((struct Library*)PPCLibBase);
  169.         } else
  170.             Printf("Can't open ppc.library V46\n");
  171.     }
  172.     CloseLibrary((struct Library*)IntuitionBase);
  173.     CloseLibrary((struct Library*)DOSBase);
  174.  
  175.     if(wbmsg) {
  176.         Forbid();
  177.         ReplyMsg(&wbmsg->sm_Message);
  178.     }
  179.     return ret;
  180. }
  181.  
  182. /*
  183.  *  Exception hook:
  184.  *    - If the exception looks like one caused by the LR bug (i.e.
  185.  *      PC==LR and bit 0 or 2 of LR set), signal our main task.
  186.  *    - otherwise, if there was an old exception hook, call it.
  187.  *    - otherwise, if the exception is a real one (not a kernel message),
  188.  *      kprintf a message to signal it to the user. I'd like to
  189.  *      fall back to the default handling (showing regs, stack, ...),
  190.  *      but I don't think it's possible. One can always use
  191.  *      PPCShowTrap to display those informations, anyway.
  192.  */
  193. BOOL SAVEDS ASM exception_func(REG(a0,struct Hook* h),
  194.                                REG(a2,void* task),
  195.                                REG(a1,struct ExceptionMsg* em)) {
  196.     if(em->Type==EXCEPTION_DATAACCESS &&
  197.        em->SRR0==em->LR &&
  198.        ((em->LR&0xf0000000)==0x20000000 ||
  199.         (em->LR&0xf0000000)==0x80000000)) {
  200.         /*
  201.          * This hook is called with task==NULL, so we don't know
  202.          * which task to restart. To work around that problem,
  203.          * the main task will scan the tasks list and retrieve
  204.          * it by checking LR's. No need to save the exception message.
  205.          */
  206.         Signal(maintask,SIGBREAKF_CTRL_F);
  207.         return TRUE;
  208.     } else if(oldhook) {
  209.         return ((hook_func*)oldhook->h_Entry)(oldhook,task,em);
  210.     } else {
  211.         if(!(em->Type&EXCEPTION_MSG))
  212.             kprintf("Exception %lx. Use PPCShowTrap for details.\n",em->Type);
  213.         return FALSE;
  214.     }
  215. }
  216.  
  217. static struct Hook hook={{NULL,NULL},(ULONG (*)())exception_func};
  218.  
  219. /*
  220.  *  Restart a task.
  221.  */
  222. void restart(void* task,ULONG lr) {
  223.     PPCSetTaskAttrsTags(task,
  224.                         PPCTASKINFOTAG_PC,&lr,
  225.                         PPCTASKINFOTAG_LR,&lr,
  226.                         TAG_END);
  227.     PPCStartTaskTags(task,PPCTASKSTARTTAG_RUN,TRUE,TAG_END);
  228. }
  229.  
  230. /*
  231.  *  Task list scanning hook. Look for tasks that have bad PC/LR,
  232.  *  and restart them.
  233.  */
  234. void SAVEDS ASM scantasks_func(REG(a2,void* task)) {
  235.     ULONG pc,lr,state;
  236.     state=PPCGetTaskAttrsTags(task,PPCTASKINFOTAG_STATE,NULL,TAG_END);
  237.     PPCGetTaskAttrsTags(task,PPCTASKINFOTAG_PC,&pc,TAG_END);
  238.     PPCGetTaskAttrsTags(task,PPCTASKINFOTAG_LR,&lr,TAG_END);
  239.     if(state==TS_WAIT && pc==lr &&
  240.        ((lr&0xf0000000)==0x20000000 || (lr&0xf0000000)==0x80000000)) {
  241.         static struct EasyStruct es={
  242.             sizeof(struct EasyStruct),0,"LRBug Exception Handler",
  243.             "LR bug caught in task\n\"%s\"",
  244.             "Continue|Suspend",
  245.         };
  246.         const char* name=(const char*)PPCGetTaskAttrsTags(task,
  247.                                                           PPCTASKINFOTAG_NAME,NULL,
  248.                                                           TAG_END);
  249.         if(!quiet)
  250.             kprintf("LR bug caught in task \"%s\" (%lx).\n",name,task);
  251.         lr&=~0xf0000000;
  252.         if(noreq)
  253.             restart(task,lr);
  254.         else {
  255.             if(EasyRequest(NULL,&es,NULL,name)==1)
  256.                 restart(task,lr);
  257.         }
  258.  
  259.     }
  260. }
  261.  
  262. void scan_tasks_list(void) {
  263.     static struct Hook scantasks_hook={{NULL,NULL},(ULONG (*)())scantasks_func};
  264.  
  265.     PPCGetTaskAttrsTags(NULL,
  266.                         PPCTASKINFOTAG_HOOK,&scantasks_hook,
  267.                         PPCTASKINFOTAG_ALLTASK,TRUE,
  268.                         TAG_END);
  269. }
  270.  
  271. /*
  272.  *  Install the exception handler and wait for events.
  273.  */
  274.  
  275. void install_handler(void) {
  276.     oldhook=(struct Hook *)PPCGetAttrsTags(PPCINFOTAG_EXCEPTIONHOOK,NULL,TAG_END);
  277.     PPCSetAttrsTags(PPCINFOTAG_EXCEPTIONHOOK,&hook,TAG_END);
  278.  
  279.     while(!(Wait(SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_F)&SIGBREAKF_CTRL_C))
  280.         scan_tasks_list();
  281.  
  282.     PPCSetAttrsTags(PPCINFOTAG_EXCEPTIONHOOK,oldhook,TAG_END);
  283. }
  284.  
  285.